package cn.xyfmzmy.proxy;

import java.lang.reflect.Field;

public class Main {

    public static void main(String[] args) throws Exception {
        // 通过MyInerfaceFactory创建代理对象并执行相应方法
        MyInterface proxyObject = MyInerfaceFactory.createProxyObject(new PrintFunctionName());
        proxyObject.func1();
        proxyObject.func2();
        proxyObject.func3();
        System.out.println("--------");
        proxyObject = MyInerfaceFactory.createProxyObject(new PrintFunctionName1());
        proxyObject.func1();
        proxyObject.func2();
        proxyObject.func3();
        System.out.println("--------");
        proxyObject = MyInerfaceFactory.createProxyObject(new LogHandler(proxyObject));
        proxyObject.func1();
        proxyObject.func2();
        proxyObject.func3();
    }

    // 自定义方法体对应的Handler,用于创建代理对象
    static class PrintFunctionName implements MyHandler {
        @Override
        public String functionBody(String methodName) {
            return "System.out.println(\""+ methodName +"\");";
        }
    }

    // 多打印个1
    static class PrintFunctionName1 implements MyHandler {
        @Override
        public String functionBody(String methodName) {
            StringBuilder sb = new StringBuilder();
            sb.append("System.out.println(1);\n")
                    .append("System.out.println(\""+ methodName +"\");");
            return sb.toString();
        }
    }

    // 在原有方法基础上，添加打印日志
    static class LogHandler implements MyHandler {

        MyInterface myInterface;

        public LogHandler(MyInterface myInterface) {
            this.myInterface = myInterface;
        }

        // LogHandler对应的MyInterface$proxy3调用原方法，用到了MyInterface myInterface;
        // 这里定义赋值逻辑，将作为构造参数传入的 myInterface(原代理对象) 赋值给新生成的 proxy(新代理对象)
        @Override
        public void setProxy(MyInterface proxy) {
            Class<? extends MyInterface> aClass = proxy.getClass();
            Field field = null;
            try {
                field = aClass.getDeclaredField("myInterface");
                field.setAccessible(true);
                field.set(proxy,myInterface);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public String functionBody(String methodName) {
            String context = "        System.out.println(\"before\");\n" +
                    "        myInterface."+ methodName +"();\n" +           // 执行原方法，这里动态的
                    "        System.out.println(\"after\");";
            return context;
        }
    }
}
